//
//  SleepModel.swift
//  MoYoung
//
//  Created by sylar on 17/2/21.
//  Copyright © 2017年 sylar. All rights reserved.
//

/// 睡眠存储，每一次存储可能是2天的数据
/// 比如： 晚上 8点睡着 - 第二天 8点醒来
/// 得到的就是 2天的 昨天的 20: 00 - 24:00 第二天的 0:00 - 8:00
///
import Foundation
import SQLite
import HandyJSON
import SwiftDate
import SQLiteValueExtension
import MYModule


open class SleepModel: NSObject, MYSQLiteTableiabe, FullDaySQLite, HandyJSON {
    
    // 晚上 8 点
    public static let constSleepStart = 20
    
    public var adress: String = ""
    
    public var id: Int64 = 0
    
    public var date: Date = Date().sqlDate()
    
    /// 深睡总时长
    public var deep: Int = 0
    
    /// 浅睡总时长
    public var light: Int = 0
    
    /// 眼动总时长
    public var rem: Int = 0
    
    /// 睡眠详情
    public var detail: [SleepDetailModel] = []
    

    /// 最后一次同步睡眠数据时间戳
    public var updateTime: Double = 0
    
    
    public var isEmpty: Bool {
        return total == 0 || detail.isEmpty
    }
    
    
    required public override init() {}
    
    
    public func updateData() {
        
        guard let _ = SleepModel.day(date: date) else {
            insert()
            return
        }
        update()
        
    }
    
   
    /// 一天 的睡眠数据拆分成每分钟的数据
    public static func flatMapSleepTypeWithMinute(date: Date) ->[Int] {
        var allTypes = (0 ..< 1440).map { _ in 0 }
        guard let today = SleepModel.day(date: date) else {
            return allTypes
        }
        
        today.sleepDetailForDays.today.forEach {
            let type = $0.type
            let start = $0.startMinute
            
            for t in 0 ..< $0.total {
                
                let index = start + t
                if index < 1440 {
                    allTypes[index] = type + 10
                }
                
            }
            
        }
        if !date.isToday && !date.isTomorrow {
            let lastDate = date + 1.days
            guard let lastDay = SleepModel.day(date: lastDate) else { return allTypes }
            
            lastDay.sleepDetailForDays.yesterday.forEach {
                let type = $0.type
                let start = $0.startMinute
                for t in 0 ..< $0.total {
                    
                    let index = start + t
                    if index < 1440 {
                        allTypes[index] = type + 10
                    }
                }
            }
            
        }
        
        return allTypes
        
    }
    

  
}


public extension SleepModel {
    
    /// 总时长
    var total: Int {
        return light + deep + rem
    }
    
    /// 获取本次睡眠入睡时间
    var fallAsleepDate: Date? {
        return detail.filter { $0.type != 0}.first?.longStartDate(with: date)
        
    }
    
    /// 获取本次睡眠醒来时间
    var awakeDate: Date? {
        return detail.last?.longEndDate(with: date)
    }
    
    /// 将睡眠详情按日期分开
    var sleepDetailForDays: SleepDetailForDay {
        
        var todays = [SleepDetailModel]()
        var yesterdays = [SleepDetailModel]()
        
        detail.forEach {
            
            if $0.isToday {
                todays.append($0)
            } else {
                yesterdays.append($0)
            }
            
        }
        
        return SleepDetailForDay(today: todays, yesterday: yesterdays)
        
    }
    
}

public extension SleepModel {
    
    /// 根据睡眠入睡清醒时间将全天的数据最对拆解成 今早入睡, 今日醒来，日常，今晚入睡4个阶段的数据
    /// - Parameters:
    ///   - datas: datas
    ///   - date: 这一次睡眠的日期
    ///   - interval: 数据间隔，间隔中间用零补位
    /// - Returns: 元组（今早入睡, 今日醒来，日常，昨日入睡）
    static func sleepTimeDataMapToTuple(datas: [Int], sleepDate: Date, minute interval: Int, addMore: Bool = true) -> (morningSleep: [Int], morningWakeUp: [Int], daily: [Int], tonightFallASleep: [Int]) {
        
        let tuple = sleepTimeDataMapToTuple(datas: datas.map({ Double($0) }), sleepDate: sleepDate, minute: interval)
        let morningSleep = tuple.morningSleep.map { Int($0) }
        let morningWakeUp = tuple.morningWakeUp.map { Int($0) }
        let daily = tuple.daily.map { Int($0) }
        let tonightFallASleep = tuple.tonightFallASleep.map { Int($0) }
        
        return (morningSleep, morningWakeUp, daily, tonightFallASleep)
    }
    
    
    /// 根据睡眠入睡清醒时间将全天的数据最对拆解成 今早入睡, 今日醒来，日常，今晚入睡4个阶段的数据
    /// - Parameters:
    ///   - datas: datas
    ///   - date: 这一次睡眠的日期
    ///   - interval: 数据间隔，间隔中间用零补位
    ///   - addMore: 是否前后多取一个
    /// - Returns: 元组（今早入睡, 今日醒来，日常，昨日入睡）
    static func sleepTimeDataMapToTuple(datas: [Double], sleepDate: Date, minute interval: Int, addMore: Bool = true) -> (morningSleep: [Double], morningWakeUp: [Double], daily: [Double], tonightFallASleep: [Double]) {
        
        if datas.filter({ $0 > 0 }).isEmpty {
            return ([], [], datas, [])
        }
        
        var today_end_minute: Int?
        var today_start_minute: Int?
        var today_fallAsleepDate: Date?
        var today_awakeDate: Date?
        
        if
            let sleepModel = SleepModel.day(date: sleepDate),
            let start = sleepModel.fallAsleepDate,
            let end = sleepModel.awakeDate {
            
            /// 算出来多少分钟
            var today_end = end.minute + end.hour * 60
            var today_start = start.minute + start.hour * 60
            
            if start.day == end.day && today_start%interval < SleepModel.constSleepStart {
                // 超过0点睡
                today_start = today_start - today_start%interval
                
            } else {
                // 0点以前睡, 多取一个
                if today_start%interval > 0 {
                    today_start = today_start - today_start%interval + interval
                }
            }
            
            // 多取一个
            if today_end%interval > 0 {
                
                today_end = today_end - today_end%interval + interval
            }
            
            today_start_minute = today_start
            today_end_minute = today_end
            today_fallAsleepDate = start
            today_awakeDate = end
            
        }
        
        var tonight_minute: Int?
        // 属于今晚晚上入睡（明天的昨天）
        let tomorrowDate = sleepDate + 1.days
        if
            let sleepModel = SleepModel.day(date: tomorrowDate),
            let start = sleepModel.fallAsleepDate,
            let end = sleepModel.awakeDate,
            end.day != start.day
        {
            
            var minute = start.minute + start.hour * 60
            // 多取一个
            if minute%interval > 0 {
                minute = minute - minute%interval
            }
            if minute < 0 {
                minute = 0
            }
            tonight_minute = minute
        }
        
        var tonight: [Double] = []
        var morningSleep: [Double] = []
        var morningAwake: [Double] = []
        var daily: [Double] = []
        datas.enumerated().forEach { i, data in
            
            let currentMinute = (i + 1) * interval
            
            if let start = today_fallAsleepDate,
               let end = today_awakeDate,
               let today_start_minute = today_start_minute,
               let today_end_minute = today_end_minute {
                
                if start.day == end.day && today_start_minute%interval < SleepModel.constSleepStart {
                    // 超过0点睡
                    
                    if currentMinute > 0 && currentMinute <= today_start_minute {
                        // 未入睡
                        morningSleep.append(data)
                        return
                        
                    } else if currentMinute > today_start_minute && currentMinute < today_end_minute  {
                        //入睡
                        morningAwake.append(data)
                        return
                    }
                    
                } else {
                    
                    // 未超过0点入睡
                    if currentMinute > 0 && currentMinute < today_end_minute  {
                        //入睡
                        morningAwake.append(data)
                        return
                    }
                }
            }
            
            if let tonight_minute = tonight_minute {
                
                if currentMinute >= tonight_minute && tonight_minute < 1440 {
                    tonight.append(data)
                    return
                }
            }
            
            daily.append(data)
            

        }
        
        return (morningSleep, morningAwake, daily, tonight)
    }
    
}


public struct SleepDetailModel : HandyJSON, StringValueExpressible {
    
    
    /// 状态 0: 清醒 1:浅睡 2: 深睡 3：快速眼动
    public var type: Int = 0
    
    /// 时⻓(分钟)
    public var total: Int = 0
    
    /// 开始时间 "HH:mm"
    public var start: String = ""
    
    /// 结束时间 "HH:mm"
    public var end: String = ""
    
    /// 将睡眠详情拆成每分钟的一个的数据（今天，昨天分开）
    public var flatMapWithMinute: SleepModel.SleepDetailForDay? {
        
        guard let startDate = start.toDate(style: .custom("HH:mm"))?.date else {
            return nil
        }
        
        let minutes = endMinute - startMinute
        
        var todayDetails = [SleepDetailModel]()
        var yestedayDetails = [SleepDetailModel]()
        
        for i in 0 ..< minutes {
            var sleepDetail = SleepDetailModel()
            sleepDetail.type = self.type
            sleepDetail.total = 1
            sleepDetail.start = (startDate + i.minutes).toString(.custom("HH:mm"))
            sleepDetail.end = (startDate + 1.minutes).toString(.custom("HH:mm"))
            if sleepDetail.isToday {
                todayDetails.append(sleepDetail)
            } else {
                yestedayDetails.append(sleepDetail)
            }
        }
        
        return SleepModel.SleepDetailForDay(today: todayDetails, yesterday: yestedayDetails)
    }
    
    
    
    public var startMinute: Int {
        guard let date = start.toDate(style: .custom("HH:mm")) else {
            return 0
        }
        return date.hour * 60 + date.minute
    }
    
    public var endMinute: Int {
        guard let date = end.toDate(style: .custom("HH:mm")) else {
            return 0
        }
        return date.hour * 60 + date.minute
        
    }
    
    
    /// 判断当前睡眠是否是今天（因为睡眠是跨天的）
    public var isToday: Bool {
        
        guard let endDate = end.toDate(style: .custom("HH:mm"))?.date else {
            return false
        }
        
        return endDate.hour < SleepModel.constSleepStart && endDate.hour > 0 && endDate.minute > 0
        
    }
    
    
    /// 得到 "yyyy-MM-dd HH:mm" 开始时间
    public func longStartDate(with date: Date) ->Date? {
        
        var startDate = date.dateAtStartOf(.day)
        let timeArray = start.components(separatedBy: ":")
        
        guard let hourStr = timeArray.first,
              let minuteStr = timeArray.last,
              let hour = Int(hourStr),
              let minute = Int(minuteStr) else {
            return nil
        }
        
        
        if hour > SleepModel.constSleepStart {
            startDate = startDate - 1.days
        }
        startDate = startDate + hour.hours + minute.minutes
        return startDate
    }
    
    /// 得到 "yyyy-MM-dd HH:mm" 结束时间
    public func longEndDate(with date: Date) ->Date? {
        var endDate = date.dateAtStartOf(.day)
        let timeArray = end.components(separatedBy: ":")
        
        guard let hourStr = timeArray.first,
              let minuteStr = timeArray.last,
              let hour = Int(hourStr),
              let minute = Int(minuteStr) else {
            return nil
        }
        
        if hour > SleepModel.constSleepStart {
            endDate = endDate - 1.days
        }
        endDate = endDate + hour.hours + minute.minutes
        return endDate
        
    }
    
    
    public init() {}
    
    
    
    public static func fromStringValue(_ stringValue: String) -> SleepDetailModel {
        return deserialize(from: stringValue) ?? SleepDetailModel()
    }
    
    public var stringValue: String {
        return self.toJSONString() ?? ""
        
    }
    
}


public extension SleepModel {
    
    struct SleepDetailForDay {
        public var today: [SleepDetailModel]
        public var yesterday: [SleepDetailModel]
    }
    
}
